A thesaurus is not a species of dinosaur

Echarts4r customisation

January 05, 2023

Echarts4r is a nice wrapper around the echarts package for Javascript. It’s easy and does a lot of things for us.

I had a vexing problem in which I basically had a stacked bar chart and upon clicking a particular series, I wanted every other cell except the one clicked to become lighter. This is a behaviour from another visualization that I was trying to mimic.

To do this, we need to write a handler which will work in echarts4r. To give an example

  cars |>
    e_charts(speed) |>
    e_scatter(dist) |>
    e_on(
      list(seriesName = "dist"),
      "function(){alert('Serie clicked')}"
    )

This is directly taken from the echarts4r guides.

To understand the guts of the echarts library, I went through the documentation and played around in the console.

I started off using this fiddle

So my primary task could be broken into 3 steps:

  1. somehow get an object to manipulate the echarts object.
  2. store all the colors and change only the clicked object color.
  3. apply the change

The following code does that:

    e_on(query = list(),
            handler ="
    function(params){ //params holds the click data
    debugger; // useful for debugging
    // create an object pointing to current scope
    window['echartsObj'+this._dom.id] = echarts.init(document.querySelector('#' + this._dom.id));
    function hexToRgb(hex) { // misc funcs to change between color spaces ,copied from SO
      var result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);
      return result ? [
        parseInt(result[1], 16),
        parseInt(result[2], 16),
        parseInt(result[3], 16)
      ] : null;
    }
    function rgbToHsl(r, g, b){
        r /= 255, g /= 255, b /= 255;
        var max = Math.max(r, g, b), min = Math.min(r, g, b);
        var h, s, l = (max + min) / 2;

        if(max == min){
            h = s = 0; // achromatic
        }else{
            var d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            switch(max){
                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                case g: h = (b - r) / d + 2; break;
                case b: h = (r - g) / d + 4; break;
            }
            h /= 6;
        }

        return [(h*360).toFixed(2), s.toFixed(2)*100, l.toFixed(2)*100];
    }
    function hslToHex(h, s, l) {
      l /= 100;
      const a = s * Math.min(l, 1 - l) / 100;
      const f = n => {
        const k = (n + h / 30) % 12;
        const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
        return Math.round(255 * color).toString(16).padStart(2, '0');  
      };
      return `#${f(0)}${f(8)}${f(4)}`;
    }  
    // get option for current object and color too
    my2 = window['echartsObj'+this._dom.id].getOption().series 
    colorss = window['echartsObj'+this._dom.id].getOption().color 
    my2.map(function (element,index) { // evverything else apart from clicked object gets dimmer
      
      element.data.map(function (data,idx) {
      
      if (params.seriesIndex == index && params.dataIndex== idx) {
      data.itemStyle = {
              
                    color: colorss[idx]} // keep same color as before
      }
    else {

      var t2 = rgbToHsl.apply(this,hexToRgb(colorss[idx]))
    t2 = t2.map(function(d){ return Number(d)}) 
    t2[2] = t2[2] + 25 // reduce luminance by 25 for all except clicked element

      data.itemStyle = {
      


      color: hslToHex.apply(this,t2) }
            }
            
            })});
          
    window['echartsObj'+this._dom.id].setOption({ // apply new options
        series: my2})
      
      }
      

    ",
      event = "click")
      
      })  

This piece of code can be modified to perform other effects by effectively examining the getoption() return object and modifying.


Narayanan Iyer

Written by Narayanan Iyer who lives and works in Mumbai. Full time R and shiny enthusiast , he spends way too much time on HN. Fluent in R,shiny, docker, Python, Javascript and C# and 6 other human languages.

You can contact him at narayanan iyer 22 at gmail dot com